#ifndef numuCCQESelection_h
#define numuCCQESelection_h

#include "SelectionBase.hxx"
#include "SubDetId.hxx"
#include "Parameters.hxx"

class numuCCQESelection: public SelectionBase{
 public:
  numuCCQESelection(bool forceBreak=true);
  virtual ~numuCCQESelection(){}

  //---- These are mandatory functions
  void DefineSteps();
  inline AnaBoxB* MakeBox();
  bool FillEventSummary(const AnaBoxB& box, AnaEventB& event, Int_t allCutsPassed[]);
  nd280Samples::SampleEnum GetSampleEnum(){return nd280Samples::kFGD1NuMuCCQE;}

};



class AnaBoxCCQE: public AnaBoxB{

public:

  AnaBoxCCQE() {
    MuonCandidate = ProtonCandidate = VetoTrack3 = NULL;
    ProtonVertex = NULL;
  }  
  virtual ~AnaBoxCCQE(){ if (ProtonVertex) delete ProtonVertex;}

  std::vector<AnaTrackB*> TrackerTracks;

  /// For storing tracks with TPC information in the bunch.
  std::vector<AnaTrackB*> TPCtracks;
  std::vector<AnaTrackB*> NegativeTPCtracksOutFV;
  std::vector<AnaTrackB*> PositiveTPCtracksOutFV;
  std::vector<AnaTrackB*> BadQuaTPCtracksInFV;
  std::vector<AnaTrackB*> BadQuaTPCtracksOutFV;

  /// For storing tracks with FGD information in the bunch.
  std::vector<AnaTrackB*> FGDtracks;
  std::vector<AnaTrackB*> FGDtracksCrossingFGD1;
  std::vector<AnaTrackB*> FGDtracksInFGD1Volume;
  std::vector<AnaTrackB*> FGDContTracksInFV;
  std::vector<AnaTrackB*> FGDNotContTracksInFV;
  std::vector<AnaTrackB*> FGDContTracksOutFV;
  std::vector<AnaTrackB*> FGDNotContTracksOutFV;

  // neut counters
  int Nmuons;
  int Nprotons;

  AnaTrackB* MuonCandidate;
  AnaTrackB* ProtonCandidate;

  AnaVertexB* ProtonVertex;

  /// For storing the veto track in branch 3.
  AnaTrackB* VetoTrack3;
  
  /// For storing the length of the muon candidate in branch 3
  double FGDlength; 

};

inline AnaBoxB* numuCCQESelection::MakeBox() {return new AnaBoxCCQE();}

namespace std_numuccqe_actions{


  void FindTracksWithTPC(const AnaEventB& event, AnaBoxCCQE& box, bool qualityCut = true, SubDetId::SubDetEnum det = SubDetId::kFGD1);
  void FindTracksWithFGDAndNoTPC(const AnaEventB& event, AnaBoxCCQE& box, SubDetId::SubDetEnum det = SubDetId::kFGD1);

  //---- cut definitions ------
  bool FGDTrackQualityCut(const AnaTrackB& track);
  bool FGDProtonPIDCut(const AnaTrackB& track);
  bool FGDMuonPIDCut(const AnaTrackB& track);

  /// Fnd the correct sense of a secondary track by comparing its start and end positions with the vertex
  void FindCorrectSense(AnaTrackB* track, AnaVertexB* vertex);

  // Go back to the original sense
  void RevertToOriginalSense(AnaTrackB* track);

  /// Check wether the track ends in BarrelEcal Volume
  bool TrackEndsInBarrelECal(const AnaTrackB& track);

  /// Check wether the track ends in SMRD Volume
  bool TrackEndsInSMRD(const AnaTrackB& track);

  /// Check wether the track ends in BarrelEcal Fiducial Volume
  bool TrackEndsInBarrelECalFV(const AnaTrackB& track);

  /// Check wether the track ends in SMRD Fiducial Volume
  bool TrackEndsInSMRDFV(const AnaTrackB& track);

  /// Check wether the track ends in FGD1 Fiducial Volume  
  bool TrackEndsInFgd1FV(const AnaTrackB& track);

}

class FillSummaryAction_numuCCQE: public StepBase{
public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;  
  StepBase* MakeClone(){return new FillSummaryAction_numuCCQE();}
};

class OneNegativeTrackCut: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new OneNegativeTrackCut();}
};

class MichelElectronCut: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new MichelElectronCut();}
};


class OneTrackerTrackCut: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new OneTrackerTrackCut();}
};

class TwoTrackerTracksCut: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new TwoTrackerTracksCut();}
};

class OnePositiveTrackCut: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new OnePositiveTrackCut();}
};

class CommonVertexCut1: public StepBase{
 public:
  CommonVertexCut1(){
    _cutX = ND::params().GetParameterI("psycheSelections.numuCCQE.CutX1"); 
    _cutY = ND::params().GetParameterI("psycheSelections.numuCCQE.CutY1"); 
    _cutZ = ND::params().GetParameterI("psycheSelections.numuCCQE.CutZ1");
  }  
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new CommonVertexCut1();}
 private:
  int _cutX;
  int _cutY;
  int _cutZ; 
};

class CommonVertexCut2: public StepBase{
 public:
  CommonVertexCut2(){
    _cutX = ND::params().GetParameterI("psycheSelections.numuCCQE.CutX2"); 
    _cutY = ND::params().GetParameterI("psycheSelections.numuCCQE.CutY2"); 
    _cutZ = ND::params().GetParameterI("psycheSelections.numuCCQE.CutZ2");
  }
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new CommonVertexCut2();}
  private:
    int _cutX;
    int _cutY;
    int _cutZ; 
};

class CommonVertexCut3: public StepBase{
 public:
  CommonVertexCut3(){
    _cutX = ND::params().GetParameterI("psycheSelections.numuCCQE.CutX3"); 
    _cutY = ND::params().GetParameterI("psycheSelections.numuCCQE.CutY3"); 
    _cutZ = ND::params().GetParameterI("psycheSelections.numuCCQE.CutZ3");
  }
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new CommonVertexCut3();}
private:
  int _cutX;
  int _cutY;
  int _cutZ; 
};

class ProtonPIDCut: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new ProtonPIDCut();}
};

class OneFGDContainedTrackCut: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new OneFGDContainedTrackCut();}
};

class FGDProtonPIDCut: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new FGDProtonPIDCut();}
};

class ExternalVetoCut3: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new ExternalVetoCut3();}
};

class OneFGD1TrackCut: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new OneFGD1TrackCut();}
};

class LongFGDTrackCut: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new LongFGDTrackCut();}
};

class FGDMuonPIDCut: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new FGDMuonPIDCut();}
};

class StoppingProtonCut: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new StoppingProtonCut();}
};

class StoppingMuonCut: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new StoppingMuonCut();}
};

class TrackEndsInBarrelECalOrSMRDCut: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new TrackEndsInBarrelECalOrSMRDCut();}
};

class TrackQualityFiducialCut3: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new TrackQualityFiducialCut3();}
};


class FindMichelElectronsAction: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new FindMichelElectronsAction();}
};


class FindTrackerTracksAction: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new FindTrackerTracksAction();}
};

class FindCorrectMuonSenseAction: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new FindCorrectMuonSenseAction();}
};

class FindCorrectProtonSenseAction: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new FindCorrectProtonSenseAction();}
};


class RevertToOriginalProtonSenseAction: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new RevertToOriginalProtonSenseAction();}
};


  /// Find Muon and Proton candidates for all topologies
class FindCandidatesAction: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new FindCandidatesAction();}
};

/// Vertex based on the HMP track
class FindProtonVertexAction: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new FindProtonVertexAction();}
};

/// Veto track for Case3
class FindVetoTrackAction3: public StepBase{
 public:
  using StepBase::Apply;
  bool Apply(const AnaEventB& event, AnaBoxB& box) const;
  StepBase* MakeClone(){return new FindVetoTrackAction3();}
};


#endif
